package com.oristand.aop;

import com.oristand.annotation.RedisCache;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * 用aop结合注解的方式,配置redis缓存策略
 *
 * @author shiyjian
 * @version 1.0
 * @date 2021/12/2 14:25
 */
@Component
@Aspect
public class RedisCacheAspect {

    /**
     * 保存redis中缓存的key
     */
    private final static List<String> REDIS_KEYS = new LinkedList<>();

    /**
     * 日志
     */
    private final static Logger logger = LoggerFactory.getLogger(RedisCacheAspect.class);

    /**
     * 操作redis存取
     */
    private RedisTemplate<String, Object> redisTemplate;

    @Pointcut("@annotation(com.oristand.annotation.RedisCache)")
    public void redisCachePoint() {

    }

    @Autowired
    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 环绕增强实现redis缓存(半成品)
     *
     * @param point 连接点,就是那个方法
     * @return 返回point执行之后的结果
     */
    @Around("redisCachePoint()")
    public Object writeReadFromRedis(ProceedingJoinPoint point) {
        logger.info("<==========开始redisCache在查询之前==========>");
        RedisCache redisCache = ((MethodSignature) point.getSignature()).getMethod().getAnnotation(RedisCache.class);
        String key = redisCache.key() + ((MethodSignature) point.getSignature()).getMethod().getName();
        if (!REDIS_KEYS.contains(key)) {
            REDIS_KEYS.add(key);
        }
        Object[] args = point.getArgs();
        StringBuilder stringBuilder = new StringBuilder(key);
        for (Object arg : args) {
            String temp = "_" + arg.toString();
            stringBuilder.append(temp);
        }
        key = stringBuilder.toString();
        try {
            if (redisCache.read()) {
                Object obj = redisTemplate.opsForValue().get(key);
                if (obj == null) {
                    logger.info("<==========redis中不存在==========>");
                    obj = point.proceed();
                    if (obj != null) {
                        if (redisCache.expired() > 0) {
                            redisTemplate.opsForValue().set(key, obj, redisCache.expired() + new Random().nextInt(30), TimeUnit.SECONDS);
                        } else {
                            redisTemplate.opsForValue().set(key, obj);
                        }
                    }
                } else {
                    logger.info("<==========redis存在==========>");
                }
                return obj;
            } else {
                Object o = point.proceed();
                Iterator<String> iterator = REDIS_KEYS.iterator();
                if (iterator.hasNext()) {
                    do {
                        String s = iterator.next();
                        redisTemplate.delete(s);
                    } while (iterator.hasNext());
                }
                REDIS_KEYS.clear();
                return o;
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return null;
    }


}
